/***********************************************************************************
**  
* @copyright (c) 2010-2019, ChengDu Duyer Technology Co., LTD. All Right Reserved.
*
************************************************************************************/
/**
* @file	    mjs_client.cpp
* @version     
* @brief      
* @author   duye
* @date	    2017-01-16
* @note 
*
* 1. 2017-01-16 duye Created this file
*/

#include <duye_type.h>
#include <duye_xml.h>
#include <duye_buffer.h>
#include <duye_logger.h>
#include <duye_cfg_mgr.h>
#include <duye_system.h>
#include <mj_net_protocol.h>
#include <mjs_reqer.h>
#include <mjs_on_action.h>
#include <mjs_mysql.h>
#include <mjs_server.h>
#include <mjs_client.h>

static const int8* DUYE_LOG_PREFIX = "mangjings.client";

MJSClient::MJSClient(const int32 sockfd, const std::string& ip, MJSOnActionMap* on_action_map, MJServer* mjserver, const ClientType& client_type) 
	: m_client_type(client_type)
	, m_sockfd(sockfd)
	, m_ip(ip)
	, m_conn_status(ON_LINE)
	, m_auth_status(AUTH_NO)
	, m_on_action_map(on_action_map)
	, m_mjserver(mjserver)
	, m_reqer(NULL) {

	m_reqer = new MJSReqer(this);
}

MJSClient::~MJSClient() {
	delete m_reqer;
}

void MJSClient::setConnStatus(const ConnStatus status) {
	m_conn_status = status;
	DUYE_WARN("client:%s conn_status change to %s", m_ip.c_str(), connStatusStr().c_str());
}

MJSClient::ConnStatus MJSClient::connStatus() {
	return m_conn_status;
}

std::string MJSClient::connStatusStr() {
	switch(m_conn_status) {
		case ON_LINE : return "online"; break;
		case OFF_LINE : return "offline"; break;
		default : return ""; break;
	}

	return "";
}

void MJSClient::setAuthStatus(const AuthStatus status) {
	if (m_auth_status == status) {
		return;
	}

	m_auth_status = status;

	if (m_client_type == CLIENT_MJW || m_auth_status != AUTH_OK) {
		return;
	}

	// query user and ip
	std::string sql = "SELECT * FROM server_info WHERE user = ? and address = ?";
	MJSMysqlResult result;
	if (!MJSMysql::ins().query(sql, MJSMysql::Params(m_user, m_ip), result)) {
		return;
	}

	if (result.empty()) {
		// insert
		sql = "INSERT INTO server_info (user, address, con_status) VALUES (?, ?, ?)";
		int32 rows = MJSMysql::ins().execute(sql, MJSMysql::Params(m_user, m_ip, connStatusStr()));
		if (rows != 1) {
			DUYE_ERROR("client:%s INSERT server_info failed", m_ip.c_str());
		} else {
			DUYE_DEBUG("client:%s INSERT server_info ok", m_ip.c_str());
		}		
	} else {
		// update server_info
		sql = "UPDATE server_info SET con_status = ? WHERE user = ? and address = ?";
		int32 rows = MJSMysql::ins().update(sql, MJSMysql::Params(connStatusStr(), m_user, m_ip));
		if (rows < 0) {
			DUYE_ERROR("client:%s store auth_status(%s) to db failed", m_ip.c_str(), connStatusStr().c_str());
		} else {
			DUYE_DEBUG("client:%s store auth_status(%s) to db ok", m_ip.c_str(), connStatusStr().c_str());
		}
	}
}

MJSClient::AuthStatus MJSClient::authStatus() {
	return m_auth_status;
}

std::string MJSClient::authStatusStr() {
	switch(m_auth_status) {
		case AUTH_NO : return "cert_no"; break;
		case AUTH_FA : return "cert_failed"; break;
		case AUTH_OK : return "cert_ok"; break;
		default : return ""; break;
	}

	return "";
}

const std::string& MJSClient::getIP() const {
	return m_ip;
}

const std::string& MJSClient::getUser() const {
	return m_user;
}

bool MJSClient::notify(const MJSInnerMsgType& msg_type, void* data) {
	switch (msg_type) {
		case MJS_INNER_AUTH_OK: {
			if (data) {
				m_user.assign((int8*)data);
				setAuthStatus(AUTH_OK);
			} else {
				DUYE_ERROR("user name is empty");
				return false;
			}
			break;
		}
		case MJS_INNER_AUTH_FA:
		case MJS_INNER_DISCONNECT:
			setAuthStatus(AUTH_FA);
			m_mjserver->removeClient(m_sockfd);
			break;	
		default:
			return this->innerNotify(msg_type, data);
			break;
	}

	return true;
}

bool MJSClient::sendToClient(const int8* data, const uint64 len) {
	if (m_conn_status == OFF_LINE) {
		DUYE_ERROR("client : %s diconnected", m_ip.c_str());
		return false;
	}

	int64 size = m_mjserver->sendToClient(m_sockfd, data, len);
	if (size < 0) {
		DUYE_ERROR("send data to client : %s failed", m_ip.c_str());
		return false;		
	}

	if ((uint64)size != len) {
		DUYE_ERROR("failed : send size = %d, send ok size = %d", len, size);
		return false;
	}

	DUYE_DEBUG("send to %s data(%d) >>> \n%s", m_ip.c_str(), len, data);

	return true;
}